﻿// Author:  Marco van Wieren <mailto:mvwieren@gmail.com>
// Year:    2012
// License: Microsoft Public License (Ms-PL)

using System;
using System.Collections.Generic;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Security;
using Microsoft.SharePoint.Taxonomy;
using Microsoft.SharePoint.Utilities;
using Mvw.SharePoint.Taxonomy.AutoTagging.Licenses;

namespace Mvw.SharePoint.Taxonomy.AutoTagging
{
    /// <summary>
    /// List Item Events
    /// </summary>
    public class WorkspaceAdminListEvents : SPItemEventReceiver
    {
        /// <summary>
        /// An item is being added.
        /// </summary>
        public override void ItemAdding(SPItemEventProperties properties)
        {
            base.ItemAdding(properties);

            // TODO The current approach cannot be used across multiple web applications
            // TODO Not sure whether the current way of retrieving the workspaceAdmin SPUser is robust
            // TODO Make it possible to set the UrlZone using a property (now hard coded to "default")
            SPSecurity.RunWithElevatedPrivileges(delegate()
            {
                try
                {
                    using (var currSite = properties.OpenSite())
                    {
                        // Trial License -> This should be commented out for the retail version 
                        if (!TrialLicense.verifyTrialStartDate(currSite.RootWeb))
                        {
                            throw new TrialLicenseExpiredException(SPUtility.GetLocalizedString("$Resources:GLOBAL_ErrorTrialLicense",
                                "SPM.Resources", currSite.RootWeb.Language) + " [WALE0010]");
                        }

                        SPSite newSite = null;
                        var webApp = currSite.WebApplication;
                        SPUser workspaceAdmin = null;
                        string siteUrl = null;

                        workspaceAdmin = currSite.RootWeb.AllUsers.GetByID(Convert.ToInt32(properties.AfterProperties["WorkspaceAdminLogin"].ToString().Trim()));

                        siteUrl = webApp.GetResponseUri(Microsoft.SharePoint.Administration.SPUrlZone.Default).ToString().RemoveLastHash() + "/" +
                                  properties.AfterProperties["WorkspaceManagedPath"].ToString().RemoveLastHash().Trim() + "/" +
                                  Guid.NewGuid().ToString();

                        var workspaceTemplateRaw = properties.AfterProperties["WorkspaceTemplate"].ToString().Trim();
                        var workspaceTemplate = workspaceTemplateRaw.Substring(workspaceTemplateRaw.IndexOf('[') + 1, workspaceTemplateRaw.Length - 2 - workspaceTemplateRaw.IndexOf('['));

                        var workspaceLCIDRaw = properties.AfterProperties["WorkspaceLCID"].ToString().Trim();
                        var workspaceLCID = workspaceLCIDRaw.Substring(workspaceLCIDRaw.IndexOf('[') + 1, workspaceLCIDRaw.Length - 2 - workspaceLCIDRaw.IndexOf('['));

                        // TODO update documentation that we don't support a second site admin in this version
                        if (webApp.SelfServiceSiteCreationEnabled)
                        {
                            newSite = currSite.SelfServiceCreateSite(
                                siteUrl,
                                properties.AfterProperties["Title"].ToString().Trim(),
                                string.Empty,
                                Convert.ToUInt32(workspaceLCID),
                                workspaceTemplate,
                                workspaceAdmin.LoginName,
                                workspaceAdmin.Name,
                                properties.AfterProperties["WorkspaceAdminEmail"].ToString().Trim(),
                                null,
                                null,
                                null);
                        }

                        if (newSite == null)
                        {
                            return;
                        }

                        // Now store the url back in the list
                        properties.AfterProperties["WorkspaceUrl"] = siteUrl;

                        // And stamp our meta data on the site collection, for that we'll grab all Taxonomy SiteColumns from the "Inheritable Columns" group
                        var workspaceTermInfoList = new WorkspaceTermInfoList();

                        var taxonomyFields = currSite.RootWeb.AvailableInheritableColumns();

                        foreach (var taxonomyField in taxonomyFields)
                        {
                            var workspaceTermInfo = new WorkspaceTermInfo(taxonomyField, properties.AfterProperties[taxonomyField.StaticName].ToString(), currSite);
                            if (workspaceTermInfo.IsValid)
                            {
                                workspaceTermInfoList.Add(workspaceTermInfo);
                            }
                        }

                        // Pass the object to the newly created site collection's RootWeb's AllProperties
                        newSite.RootWeb.AllProperties["WorkspaceTermInfo"] = workspaceTermInfoList.ToString();
                        // And set inheritance to true by default (this property can be edited by the end user via ManageWorkspaceTermInfo)
                        newSite.RootWeb.AllProperties["WorkspaceTermInfoInherit"] = true.ToString();
                        newSite.RootWeb.Update();

                        // Enable the required features
                        newSite.RootWeb.EnsureRequiredFeatures(true, true, false);

                        // And with the WorkspaceTermInfo set run the meta data inheritance job
                        // Since we're only adding a new item there are no other webs below the
                        // new site's root web so the job don't need to run recursively
                        newSite.RootWeb.InheritWorkspaceTermInfo(false);

                        newSite.Dispose();

                        // Ensure the error field is blank
                        properties.AfterProperties["WorkspaceLatestError"] = string.Empty;
                    }

                }
                catch (Exception ex)
                {
                    if (ex is TrialLicenseExpiredException)
                    {
                        this.EventFiringEnabled = false;
                        properties.RedirectUrl = "/_layouts/AutoTagging/TrialLicenseError.aspx";
                        properties.Status = SPEventReceiverStatus.CancelWithRedirectUrl;
                    }
                    else
                    {
                        properties.AfterProperties["WorkspaceLatestError"] = ex.Message;
                    }
                }
            });
        }

        /// <summary>
        /// An item is being updated.
        /// </summary>
        public override void ItemUpdating(SPItemEventProperties properties)
        {
            SPSecurity.RunWithElevatedPrivileges(delegate()
            {
                try
                {
                    // Get a reference to the workspace currently being updated
                    if (properties.ListItem["WorkspaceUrl"] != null)
                    {
                        // Get a reference to the admin site (the parent site of the web hosting the workspace list)
                        var adminSite = properties.OpenSite();

                        // Trial License -> This should be commented out for the retail version 
                        if (!TrialLicense.verifyTrialStartDate(adminSite.RootWeb))
                        {
                            throw new TrialLicenseExpiredException(SPUtility.GetLocalizedString("$Resources:GLOBAL_ErrorTrialLicense",
                                "SPM.Resources", adminSite.RootWeb.Language) + " [WALE0010]");
                        }

                        SPSite siteBeingUpdated = null;

                        siteBeingUpdated = new SPSite(new SPFieldUrlValue(properties.ListItem["WorkspaceUrl"].ToString()).Url);

                        // First of all, check whether the site needs to be updated at all
                        if (siteBeingUpdated.RootWeb.AllProperties["WorkspaceTermInfoInherit"] != null)
                        {
                            try
                            {
                                if (!bool.Parse(siteBeingUpdated.RootWeb.AllProperties["WorkspaceTermInfoInherit"].ToString()))
                                {
                                    return;
                                }
                            }
                            catch { }

                        }
                        
                        // Ensure that the Taxonomy infrastructure is enabled
                        siteBeingUpdated.RootWeb.EnsureRequiredFeatures(true, false, false);

                        // And stamp our meta data on the site collection, for that we'll grab all Taxonomy SiteColumns from the "Inheritable Columns" group
                        var workspaceTermInfoList = new WorkspaceTermInfoList();

                        var taxonomyFields = adminSite.RootWeb.AvailableInheritableColumns();

                        foreach (var taxonomyField in taxonomyFields)
                        {
                            var workspaceTermInfo = new WorkspaceTermInfo(taxonomyField, properties.AfterProperties[taxonomyField.StaticName].ToString(), adminSite);
                            if (workspaceTermInfo.IsValid)
                            {
                                workspaceTermInfoList.Add(workspaceTermInfo);
                                siteBeingUpdated.RootWeb.EnsureTaxonomyField(workspaceTermInfo, true); 
                            }
                        }

                        siteBeingUpdated.RootWeb.AllProperties["WorkspaceTermInfo"] = workspaceTermInfoList.ToString();
                        siteBeingUpdated.RootWeb.Update();

                        // Check whether list items should be updated
                        var updateListItems = false;
                        if (adminSite.RootWeb.AllProperties["WorkspacesSettings"] != null)
                        {
                            var dict = adminSite.RootWeb.AllProperties["WorkspacesSettings"].ToString().GetDictionary();

                            if (dict.ContainsKey("WSAlwaysUpdateListElements"))
                            {
                                updateListItems = bool.Parse(dict["WSAlwaysUpdateListElements"]);
                            }
                        }

                        adminSite.Dispose();

                        siteBeingUpdated.RootWeb.InheritWorkspaceTermInfoRecursively(updateListItems);

                        siteBeingUpdated.Dispose();

                        properties.AfterProperties["WorkspaceLatestError"] = string.Empty;
                    }
                }
                catch (Exception ex)
                {
                    if (ex is TrialLicenseExpiredException)
                    {
                        this.EventFiringEnabled = false;
                        properties.RedirectUrl = "/_layouts/AutoTagging/TrialLicenseError.aspx";
                        properties.Status = SPEventReceiverStatus.CancelWithRedirectUrl;
                    }
                    else
                    {
                        properties.AfterProperties["WorkspaceLatestError"] = ex.Message;
                    }
                }
            });
            base.ItemUpdating(properties);
        }

        /// <summary>
        /// An item is being deleted.
        /// </summary>
        public override void ItemDeleting(SPItemEventProperties properties)
        {
            SPSecurity.RunWithElevatedPrivileges(delegate()
            {
                // Check whether list items should be deleted according to the settings
                var deleteListItems = false;

                if (properties.List.ParentWeb.AllProperties["WorkspacesSettings"] != null)
                {
                    var dict = properties.List.ParentWeb.AllProperties["WorkspacesSettings"].ToString().GetDictionary();
                    try
                    {
                        if (dict.ContainsKey("WSDeleteWorkspaces"))
                        {
                            deleteListItems = bool.Parse(dict["WSDeleteWorkspaces"]);
                        }
                    }
                    catch { }
                }

                // Get a reference to the workspace currently being updated
                if (deleteListItems && properties.ListItem["WorkspaceUrl"] != null)
                {
                    try
                    {
                        var siteBeingUpdated = new SPSite(new SPFieldUrlValue(properties.ListItem["WorkspaceUrl"].ToString()).Url);
                        siteBeingUpdated.Delete();
                        siteBeingUpdated.Dispose();
                    }
                    catch { }
                }
            });
            base.ItemDeleting(properties);
        }
    }
}
